/** @file    BuildingObjectGraphicsItem.cpp
 *  @author  Alessandro Polo
 *  @version $Id: BuildingObjectGraphicsItem.cpp 2826 2010-08-02 10:13:45Z alex $
 *  @brief
 * File containing methods for the wosh::gui::BuildingObjectGraphicsItem class.
 * The header for this class can be found in BuildingObjectGraphicsItem.h, 
 * check that file for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include "BuildingObjectGraphicsItem.h"

 #include <framework/gui/widgets/wCore_PropertiesProvider.h>
 #include <framework/gui/WidgetFileSelector.h>
 #include <framework/gui/bundles/services/FormBuildingManager.h>
 
 #include <core/Response.h>
 #include <core/Request.h>
 #include <core/Fact.h>

 #include <framework/building/Appliance.h>
 #include <framework/building/AppliancesCommon.h>
 #include <framework/building/AudioBox.h>
 #include <framework/building/Door.h>
 #include <framework/building/House.h>
 #include <framework/building/Floor.h>
 #include <framework/building/Room.h>
 #include <framework/building/Window.h>

 #include <QtGui/QMenu>
 #include <QtGui/QGraphicsSceneContextMenuEvent>
 #include <QtGui/QMessageBox>
 #include <QtGui/QPen>


using namespace std;
namespace wosh {
 namespace gui {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

BuildingObjectGraphicsItem::BuildingObjectGraphicsItem( IBuildingObjectGraphicsItemListener* parent )
	: QGraphicsPolygonItem(), WoshObject() {
	this->listener = parent;

	this->contextMenu = NULL;
	this->contextMenuChildren = NULL;
	this->objectAction = NULL;
	this->editAction = NULL;
	this->propertiesAction = NULL;
	this->methodsAction = NULL;
	this->visibleAction = NULL;
	this->moveableAction = NULL;
	this->moveToFrontAction = NULL;
	this->moveToBackAction = NULL;

    setFlags(ItemIsSelectable);// | ItemIsMovable);
    setAcceptsHoverEvents(true);

	QColor color = QColor(qrand()%32*8,qrand()%32*8,qrand()%32*8);

	int z = qrand()%256;
	QColor color2 = QColor(z,z,z);

	this->setPen( QPen((QColor(Qt::black)) ));
	this->setBrush(this->defBrush);
	this->defBrush = QBrush(color, Qt::Dense6Pattern);

	// BLINKING STUFF
	this->blinkBrush = QBrush(QColor(Qt::red), Qt::Dense6Pattern);
	this->blinking = false;
	this->blinkingTs = 0;
 }

BuildingObjectGraphicsItem::~BuildingObjectGraphicsItem() {
	if ( this->contextMenu != NULL ) 
		delete this->contextMenu;
 }

BuildingObjectGraphicsItem* BuildingObjectGraphicsItem::createItemOf( const string& itemType, IBuildingObjectGraphicsItemListener* parent ) {
	if ( itemType == "wosh::building::AudioBox" )
		return new BuildingObjectGraphicsItemAudio(parent);

	if ( itemType == "wosh::building::Light" )
		return new BuildingObjectGraphicsItemLight(parent);

	if ( itemType == "wosh::building::Door" )
		return new BuildingObjectGraphicsItemDoor(parent);

	if ( itemType == "wosh::building::Window" )
		return new BuildingObjectGraphicsItemWindow(parent);

	return new BuildingObjectGraphicsItem(parent);
 }

WRESULT BuildingObjectGraphicsItem::configureFor( const wosh::building::BuildingObject* bobj ) {
	if ( bobj == NULL ) {
		return WRET_ERR_PARAM;
	 }
	setRemoteName(bobj->getName());
	setRemoteType(bobj->getInterfaces().getImplementedClass().getName());
	setRemoteURI(bobj->getURI());

	QPointF ppos;
	ppos.setX(bobj->getGeometry().getPosition().x);
	ppos.setY(bobj->getGeometry().getPosition().y);
	setPos(ppos);
	this->height = bobj->getGeometry().getPosition().z;

	//temp
	QPolygonF ppolygon( QRectF(0,0, bobj->getGeometry().getBoundingBox().y, bobj->getGeometry().getBoundingBox().x ));
	setPolygon(ppolygon);

	drawUpdate();
	update();

	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItem::blink( bool on ) {
	if ( on )
		this->blinkingTs = Utilities::std_time();
	else
		this->blinkingTs = 0;
 }
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItem::drawUpdate() {
	uint hashValue = qHash(this->getRemoteName().c_str());
	int red = 156 + (hashValue & 0x3F);
	int green = 156 + ((hashValue >> 6) & 0x3F);
	int blue = 156 + ((hashValue >> 12) & 0x3F);
	QColor color(red, green, blue);

	if ( this->getRemoteType() == "wosh::building::House" ) {
		color.fromRgb(71, 117, 255, 200);
	 }
	else if ( this->getRemoteType() == "wosh::building::Garden" ) {
		color.fromRgb(51, 204, 0, 180);
	 }
	else if ( this->getRemoteType() == "wosh::building::Floor" ) {

	 }

	setBrush(color);
 }

void BuildingObjectGraphicsItem::remoteObject_updated() {
	this->setToolTip(QString("%1 [%2] {%3}")
						.arg(this->getRemoteName().c_str())
						.arg(this->getRemoteType().c_str())
						.arg(this->getRemoteURI().toString().c_str()) );
	
	if ( this->objectAction != NULL )
		this->objectAction->setText(this->getRemoteName().c_str());

	drawUpdate();
	update();
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItem::parseMessage( const Message& message ) {
	if ( message.getContent()->isResponse() ) {
		const wosh::Response* response = message.getContent()->asResponse();
		if ( response->getMethod() == _METHOD_GetProperties || response->getMethod() == _METHOD_ListProperties ) {
			if ( response->getData()->isKindOf<Table>() ) {
				const wosh::Table* bobjTable = response->getData()->as<Table>();
				for(unsigned int i=0; i<bobjTable->getRows(); i++) {
					const ISerializable* objCol1 = bobjTable->get(i,0);
					if ( objCol1 == NULL ) continue;
					if ( objCol1->isKindOf<Property>() ) {
						const wosh::Property* propObj= objCol1->as<Property>();
						this->setProperty( propObj->getKey(), propObj->getValue() );
					 }
					const ISerializable* objCol2 = bobjTable->get(i,1);
					if ( objCol2 == NULL ) continue;
					if ( objCol1->isKindOf<Variant>() && objCol2->isKindOf<Variant>() ) {
						const wosh::Variant* nameData= dynamic_cast<const wosh::Variant*>(objCol1);
						const wosh::Variant* valueData= dynamic_cast<const wosh::Variant*>(objCol2);
						this->setProperty( nameData->toString(), *valueData );
					 }
				 }
				update();
			}
		}
	 }
	else if ( message.getContent()->isFact() ) {
		const wosh::Fact* fact = message.getContent()->asFact();
		if ( fact->getEvent() == "PresenceChanged" ) {
			if ( !fact->hasData() )
				return;
			if ( !fact->getData()->isKindOf<Variant>() )
				return;
			const wosh::Variant* factData = dynamic_cast<const wosh::Variant*>(fact->getData());
			if ( factData == NULL ) return;
			if ( *factData == "DETECTED" )
				blink(true);
			else
				blink(false);

			return;
		 }
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool BuildingObjectGraphicsItem::setProperty( const string& key, const Variant& value ) {
	 if ( key == "Position") {
	 	double x = 0;
		double y = 0;
		QPointF ppos;
		parseString( value.toString().c_str(), x, y );
		ppos.setX(x);
		ppos.setY(y);
		this->setPos(ppos);
	 }
	else if ( key == "Height") {
		this->height = value.toDouble(0.0);
	 }
	else if ( key == "Geometry") {
		QStringList vList = QString(value.toString().c_str()).split(";", QString::SkipEmptyParts);
		QPolygonF ppolygon;
		QPointF ver;
	 	double x = 0;
		double y = 0;
		for(int i=0; i<vList.size(); i++) {
			parseString( vList.at(i), x, y );
			ver.setX(x);
			ver.setY(y);
			ppolygon.append(ver);
		 }
		this->setPolygon(ppolygon);
		drawUpdate();
		update();
	 }
	else
		return false;
	return true;
 }

Variant* BuildingObjectGraphicsItem::getProperty( const string& key ) const {
	if ( key == "Position") {
		QString posStr = QString("(%1,%2)").arg(this->pos().x()).arg(this->pos().y());
		return new Variant(posStr.toLatin1().data());
	 }
	else if ( key == "Geometry") {
		QStringList geomStr;
		for(int i=0; i<this->polygon().size(); i++) {
			QString pointStr = QString("(%1,%2)").arg(this->polygon().at(i).x()).arg(this->polygon().at(i).y());
			geomStr.append(pointStr);
		 }
		return new Variant(geomStr.join(";").toLatin1().data());
	 }
	return NULL;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool BuildingObjectGraphicsItem::raiseMessage( Message* message ) {
	if ( this->listener == NULL ) return false;
	this->listener->item_event( message, this );
	return true;
 }

bool BuildingObjectGraphicsItem::raiseMessage( MessageContent* content ) {
	if ( this->listener == NULL ) return false;
	this->listener->item_event( new Message(content), this );
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItem::advance( int phase ) {
	if ( phase == 0 ) {
		return;
	 }
	if ( this->blinkingTs > 0 ) {
		long elapsed = Utilities::std_time() - this->blinkingTs;
		if ( elapsed > 60 )
			this->blinkingTs = 0;
		else {
			if ( this->blinking )
				this->setBrush(this->blinkBrush);
			else
				this->setBrush(this->defBrush);
			this->blinking = !this->blinking;
		}
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItem::buildContextMenu() {
	this->contextMenu = new QMenu();

	this->objectAction = this->contextMenu->addAction(this->getRemoteName().c_str());
	this->objectAction->setEnabled(false);
	this->contextMenu->addSeparator();

	this->editAction = this->contextMenu->addAction( QObject::tr("Edit") );
	this->propertiesAction = this->contextMenu->addAction( QObject::tr("Properties..") );
	this->methodsAction = this->contextMenu->addAction( QObject::tr("Methods..") );

	QMenu* menuMove = new QMenu(this->contextMenu);
	this->contextMenu->addMenu(menuMove);
	menuMove->setTitle( QObject::tr("Move to") );
	this->moveToFrontAction = menuMove->addAction( QObject::tr("Front") );
	this->moveToBackAction = menuMove->addAction( QObject::tr("Back") );

	this->moveableAction = this->contextMenu->addAction( QObject::tr("Moveable") );
	this->moveableAction->setCheckable(true);

	this->visibleAction = this->contextMenu->addAction( QObject::tr("Visible") );
	this->visibleAction->setCheckable(true);

	this->contextMenuChildren = new QMenu(this->contextMenu);
	this->contextMenuChildren->setTitle("Children");
	this->contextMenu->addMenu(this->contextMenuChildren);
 }

void BuildingObjectGraphicsItem::updateContextMenu() {
	this->objectAction->setText(this->getRemoteName().c_str());
	this->moveableAction->setChecked( this->flags() & ItemIsMovable );
	this->visibleAction->setChecked(this->isVisible());

	this->contextMenuChildren->clear();
	if ( !this->childItems().isEmpty() ) {
		for(int i=0; i<this->childItems().size(); i++ ) {
			BuildingObjectGraphicsItem* item = dynamic_cast<BuildingObjectGraphicsItem*>(this->childItems().at(i));
			this->contextMenuChildren->addAction(item->getRemoteName().c_str());
		}
	}
 }

void BuildingObjectGraphicsItem::contextMenuAction( QAction *selectedAction ) {
	if ( selectedAction == NULL ) {
	 }
	else if ( selectedAction == this->propertiesAction ) {
		wCore_PropertiesProvider* propWidget = new wCore_PropertiesProvider();
		propWidget->setTargetURI(this->getRemoteURI());
		propWidget->setWindowTitle( QString("%1 [%2]").arg(this->getRemoteName().c_str()).arg(this->getRemoteURI().toString().c_str()) );
		propWidget->refreshAll();
		propWidget->show();
	 }
	else if ( selectedAction == this->visibleAction ) {
		this->setVisible(this->visibleAction->isChecked());
	 }
	else if ( selectedAction == this->moveableAction ) {
		this->setFlag(ItemIsMovable, this->moveableAction->isChecked());
	 }

	else if ( selectedAction == this->moveToFrontAction ) {
		this->setZValue(this->zValue()+1);
	 }
	else if ( selectedAction == this->moveToBackAction ) {
		this->setZValue(this->zValue()-1);
	 }
}

void BuildingObjectGraphicsItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
	if ( this->contextMenu == NULL ) buildContextMenu();
	if ( this->contextMenu == NULL ) return;
	updateContextMenu();

	QAction* selectedAction = this->contextMenu->exec(event->screenPos());

	contextMenuAction(selectedAction);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

QVariant BuildingObjectGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value) {
	if (change == ItemPositionHasChanged) {
		QPointF oldPos = this->pos();
		QPointF newPos = value.toPointF();
//		QMessageBox::warning(NULL, "TODO", QString("%1 %2 => %3 %4").arg(oldPos.x()).arg(oldPos.y()).arg(newPos.x()).arg(newPos.y()) );
    }
	return QGraphicsItem::itemChange(change, value);
 }




//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

BuildingObjectGraphicsItemAudio::BuildingObjectGraphicsItemAudio( IBuildingObjectGraphicsItemListener* parent )
	: BuildingObjectGraphicsItem(parent) {
	this->contextMenuSynch = NULL;
	this->stopAction = NULL;
	this->muteAction = NULL;
	this->volumeUpAction = NULL;
	this->volumeDownAction = NULL;

	this->setBrush( QBrush(Qt::TransparentMode) );
	this->setPen( QPen(Qt::NoPen) );

	QPixmap defPix(":/graph/var/extras/graph/wosh.building.AudioBox.png");
	this->pixmap = defPix.scaled(25, 25, Qt::KeepAspectRatio, Qt::FastTransformation );

	QPolygonF rect;
	QPointF size;
	size.setX(this->pixmap.height());
	size.setY(this->pixmap.width());
	if (size.x() < 1)	size.setX(25);
	if (size.y() < 1)	size.setY(25);

	rect.append( QPointF(0,0) );
	rect.append( QPointF(size.x(),0) );
	rect.append( QPointF(size.x(),size.y()) );
	rect.append( QPointF(0,size.y()) );
	BuildingObjectGraphicsItem::setPolygon(rect);
 }

void BuildingObjectGraphicsItemAudio::setPolygon( const QPolygonF& polygon ) {
(void)polygon;
 }


void BuildingObjectGraphicsItemAudio::paint(QPainter *painter, const QStyleOptionGraphicsItem * option, QWidget *parent ) {
	BuildingObjectGraphicsItem::paint(painter, option, parent );
	painter->drawPixmap(0, 0, this->pixmap);
 }


void BuildingObjectGraphicsItemAudio::buildContextMenu() {
	BuildingObjectGraphicsItem::buildContextMenu();
	this->playAction = new QAction( QObject::tr("Play.."), this->contextMenu);
	this->contextMenu->insertAction(this->editAction, this->playAction);
	this->stopAction = new QAction( QObject::tr("Stop"), this->contextMenu);
	this->contextMenu->insertAction(this->editAction, this->stopAction);
	this->muteAction = new QAction( QObject::tr("Mute"), this->contextMenu);
	this->muteAction->setCheckable(true);
	this->contextMenu->insertAction(this->editAction, this->muteAction);

	this->volumeUpAction = new QAction( QObject::tr("Volume Up"), this->contextMenu);
	this->contextMenu->insertAction(this->editAction, this->volumeUpAction);
	this->volumeDownAction = new QAction( QObject::tr("Volume Down"), this->contextMenu);
	this->contextMenu->insertAction(this->editAction, this->volumeDownAction);

	this->contextMenuSynch = new QMenu(this->contextMenu);
	this->contextMenuSynch->setTitle( QObject::tr("Sych with") );
	this->contextMenu->insertMenu(this->editAction, this->contextMenuSynch);

	this->contextMenu->insertSeparator(this->editAction);
 }

void BuildingObjectGraphicsItemAudio::updateContextMenu() {
	BuildingObjectGraphicsItem::updateContextMenu();
	this->contextMenuSynch->clear();
	if ( this->listener == NULL )
		this->contextMenuSynch->setEnabled(false);
	else {
		QStringList others;// = this->listener->getItemsNameByType(this->getRemoteType());
		QString myName(this->getRemoteName().c_str());
		for(int i=0; i<others.size(); i++) {
			if ( others.at(i) == myName ) continue;
			QAction* action = new QAction( others.at(i), this->contextMenuSynch);
			this->contextMenuSynch->insertAction(this->editAction, action);
		}
	 }
 }


void BuildingObjectGraphicsItemAudio::contextMenuAction( QAction* selectedAction ) {
	if ( selectedAction == this->playAction ) {
		WidgetFileSelector* fSel = new WidgetFileSelector();
		fSel->setRootPath("$MUSIC");
		if ( fSel->exec() == QDialog::Accepted ) {
			raiseMessage( new Request(_AudioBox_METHOD_play, new Variant(fSel->getItemPath().getPath()) ) );
		 }
		delete fSel;
		return;
	 }
	else if ( selectedAction == this->stopAction ) {
		raiseMessage( new Request(_AudioBox_METHOD_stop) );
		return;
	 }
	else if ( selectedAction == this->muteAction ) {
		string onoff = "off";
		if ( selectedAction->isChecked() )
			onoff = "on";
		raiseMessage( new Request(_AudioBox_METHOD_mute, new Variant(onoff)) );
		return;
	 }
	else if ( selectedAction == this->volumeUpAction ) {
		raiseMessage( new Request(_AudioBox_METHOD_volume_up) );
		return;
	 }
	else if ( selectedAction == this->volumeDownAction ) {
		raiseMessage( new Request(_AudioBox_METHOD_volume_down) );
		return;
	 }
	BuildingObjectGraphicsItem::contextMenuAction(selectedAction);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

BuildingObjectGraphicsItemLight::BuildingObjectGraphicsItemLight( IBuildingObjectGraphicsItemListener* parent )
	: BuildingObjectGraphicsItem(parent) {
	this->turnOnAction = NULL;
	this->turnOffAction = NULL;
	this->dimAction = NULL;
	this->brightAction = NULL;

	this->state = 2;
	this->setBrush( QBrush(QColor(Qt::blue)) );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemLight::parseMessage( const Message& message ) {
	if ( message.getContent()->isFact() ) {
		const wosh::Fact* fact = message.getContent()->asFact();
		if ( fact->getEvent() == "StateChanged" ) {
			if ( !fact->hasData() )
				return;
			if ( fact->getData()->isKindOf<Variant>() ) {
				const wosh::Variant* factData = dynamic_cast<const wosh::Variant*>(fact->getData());
				if ( factData == NULL ) return;
				if ( *factData == "ON" )
					turned(1);
				else if ( *factData == "OFF" )
					turned(0);
				else
					turned(-1);
			 }
			else if ( fact->getData()->isKindOf<List>() ) {
//				const wosh::List* list = dynamic_cast<const wosh::List*>(fact->getData());
//				if ( factList->indexOf(0).getData() == "FADED" ) {
//					int value = factList->get(1).toInteger(0);
//					turned(value);
//				 }
//				else
//					turned(-1);
			 }
			return;
		 }
	 }
	BuildingObjectGraphicsItem::parseMessage( message );
 }

bool BuildingObjectGraphicsItemLight::setProperty( const string& key, const Variant& value ) {
	 if ( key == _BuildingObject_KEY_State ) {
		if ( value == "OFF" )
			turned(0);
		else if ( value == "ON" )
			turned(1);
		else {
			turned(101);
		 }
	  }
	 else if ( key == _Appliance_KEY_Level ) {
		if ( value.toInteger(-1) == 0 )
			turned(0);
		else if ( value.toInteger(-1) == 100 )
			turned(100);
		else {
			turned(value.toInteger(-1));
		 }
	  }
	return BuildingObjectGraphicsItem::setProperty(key, value);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemLight::turned( short onoff ) {
	this->state = onoff;
	drawUpdate();
	update();
	if ( onoff < 0 || onoff > 1 ) {
		if ( this->turnOnAction != NULL )
			this->turnOnAction->setChecked(false);
		if ( this->turnOffAction != NULL )
			this->turnOffAction->setChecked(false);
		return;
	 }
	if ( this->turnOnAction != NULL )
		this->turnOnAction->setChecked(onoff);
	if ( this->turnOffAction != NULL )
		this->turnOffAction->setChecked(!onoff);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemLight::drawUpdate() {
	switch(this->state) {
		case 0: {
				this->setBrush( QBrush(QColor(Qt::blue)) );
				update();
				break;
			 }
		case 1: {
				this->setBrush( QBrush(QColor(Qt::yellow) ) );
				update();
				break;
			 }
		default: {
			this->setBrush( QBrush(QColor(Qt::darkYellow) ) );
				///@bug todo
				update();
				break;
			 }
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemLight::buildContextMenu() {
	BuildingObjectGraphicsItem::buildContextMenu();
	this->turnOnAction = new QAction( QObject::tr("Turn on"), this->contextMenu);
	this->turnOnAction->setCheckable(true);
	this->contextMenu->insertAction(this->editAction, this->turnOnAction);
	this->turnOffAction = new QAction( QObject::tr("Turn off"), this->contextMenu);
	this->turnOffAction->setCheckable(true);
	this->contextMenu->insertAction(this->editAction, this->turnOffAction);
	this->dimAction = new QAction( QObject::tr("Dim"), this->contextMenu);
	this->contextMenu->insertAction(this->editAction, this->dimAction);
	this->brightAction = new QAction( QObject::tr("Bright"), this->contextMenu);
	this->contextMenu->insertAction(this->editAction, this->brightAction);
	this->contextMenu->insertSeparator(this->editAction);
 }

void BuildingObjectGraphicsItemLight::updateContextMenu() {
	BuildingObjectGraphicsItem::updateContextMenu();
 }

void BuildingObjectGraphicsItemLight::contextMenuAction( QAction* selectedAction )
 {
	if ( selectedAction == this->turnOnAction ) {
		raiseMessage( new Request(_Appliance_METHOD_on) );
		return;
	 }
	else if ( selectedAction == this->turnOffAction ) {
		raiseMessage( new Request(_Appliance_METHOD_off) );
		return;
	 }
	else if ( selectedAction == this->dimAction ) {
		raiseMessage( new Request(_Appliance_METHOD_dim) );
		return;
	 }
	else if ( selectedAction == this->brightAction ) {
		raiseMessage( new Request(_Appliance_METHOD_bright) );
		return;
	 }
	BuildingObjectGraphicsItem::contextMenuAction(selectedAction);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

BuildingObjectGraphicsItemDoor::BuildingObjectGraphicsItemDoor( IBuildingObjectGraphicsItemListener* parent )
	: BuildingObjectGraphicsItem(parent) {
	this->openAction = NULL;
	this->state = 2;
	this->setBrush( QBrush(QColor(Qt::green)) );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemDoor::parseMessage( const Message& message ) {
	if ( message.getContent()->isFact() ) {
		const wosh::Fact* fact = message.getContent()->asFact();
		if ( fact->getEvent() == _Door_EVENT_DoorStateChanged ) {
			if ( !fact->hasData() )
				return;
			if ( fact->getData()->isKindOf<Variant>() ) {
				const wosh::Variant* factData = dynamic_cast<const wosh::Variant*>(fact->getData());
				if ( factData == NULL ) return;
				if ( *factData == "ON" )
					opened(1);
				else if ( *factData == "OFF" )
					opened(0);
				else
					opened(-1);
			 }
			return;
		 }
	 }
	BuildingObjectGraphicsItem::parseMessage( message );
 }

bool BuildingObjectGraphicsItemDoor::setProperty( const string& key, const Variant& value ) {
	 if ( key == _Door_EVENT_DoorStateChanged ) {
		 if ( value == "OPENED" )
			opened(0);
		 else if ( value == "CLOSED" )
			opened(1);
		 else
			opened(2);
	  }
	return BuildingObjectGraphicsItem::setProperty(key, value);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemDoor::opened( short onoff ) {
	this->state = onoff;
	drawUpdate();
	if ( onoff < 0 || onoff > 1 ) {
		if ( this->openAction != NULL )
			this->openAction->setChecked(false);
		return;
	 }
	if ( this->openAction != NULL )
		this->openAction->setChecked(onoff);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemDoor::drawUpdate()
 {
	switch(this->state) {
		case 0: {
				this->setBrush( QBrush(QColor(Qt::green)) );
				update();
				break;
			 }
		case 1: {
				this->setBrush( QBrush(QColor(Qt::red) ) );
				update();
				break;
			 }
		case 2: {
				this->setBrush( QBrush(QColor(Qt::darkCyan) ) );
				update();
				break;
			 }
		default: {
				break;
			 }
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemDoor::buildContextMenu() {
	BuildingObjectGraphicsItem::buildContextMenu();
	this->openAction = new QAction( QObject::tr("Open"), this->contextMenu);
//	this->openAction->setCheckable(true);
	this->contextMenu->insertAction(this->editAction, this->openAction);
	this->contextMenu->insertSeparator(this->editAction);
 }

void BuildingObjectGraphicsItemDoor::updateContextMenu() {
	BuildingObjectGraphicsItem::updateContextMenu();
 }

void BuildingObjectGraphicsItemDoor::contextMenuAction( QAction* selectedAction ) {
	if ( selectedAction == this->openAction ) {
		raiseMessage( new Request(_Door_METHOD_open) );
		return;
	 }
	BuildingObjectGraphicsItem::contextMenuAction(selectedAction);
 }


//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

BuildingObjectGraphicsItemWindow::BuildingObjectGraphicsItemWindow( IBuildingObjectGraphicsItemListener* parent )
	: BuildingObjectGraphicsItem(parent) {
	this->slideUpAction = NULL;
	this->slideDownAction = NULL;
	this->state = 2;
	this->setBrush( QBrush(QColor(Qt::green)) );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemWindow::parseMessage( const Message& message ) {
	if ( message.getContent()->isFact() ) {
		const wosh::Fact* fact = message.getContent()->asFact();
		if ( fact->getEvent() == _Door_EVENT_DoorStateChanged ) {
			if ( !fact->hasData() )
				return;
			if ( fact->getData()->isKindOf<Variant>() ) {
				const wosh::Variant* factData = dynamic_cast<const wosh::Variant*>(fact->getData());
				if ( factData == NULL ) return;
				if ( *factData == "ON" )
					opened(1);
				else if ( *factData == "OFF" )
					opened(0);
				else
					opened(-1);
			 }
			return;
		 }
	 }
	BuildingObjectGraphicsItem::parseMessage( message );
 }

bool BuildingObjectGraphicsItemWindow::setProperty( const string& key, const Variant& value ) {
	 if ( key == _Window_EVENT_WindowStateChanged ) {
		 if ( value == "OPENED" )
			opened(0);
		 else if ( value == "CLOSED" )
			opened(1);
		 else
			opened(2);
	  }
	return BuildingObjectGraphicsItem::setProperty(key, value);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemWindow::opened( short onoff ) {
	this->state = onoff;
	drawUpdate();

 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemWindow::drawUpdate() {
	switch(this->state) {
		case 0: {
				this->setBrush( QBrush(QColor(Qt::green)) );
				update();
				break;
			 }
		case 1: {
				this->setBrush( QBrush(QColor(Qt::red) ) );
				update();
				break;
			 }
		case 2: {
				this->setBrush( QBrush(QColor(Qt::darkCyan) ) );
				update();
				break;
			 }
		default: {
				break;
			 }
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObjectGraphicsItemWindow::buildContextMenu() {
	BuildingObjectGraphicsItem::buildContextMenu();
	this->slideUpAction = new QAction( QObject::tr("Slide Up"), this->contextMenu);
	this->slideUpAction->setCheckable(true);
	this->contextMenu->insertAction(this->editAction, this->slideUpAction);
	this->slideDownAction = new QAction( QObject::tr("Slide Down"), this->contextMenu);
	this->slideDownAction->setCheckable(true);
	this->contextMenu->insertAction(this->editAction, this->slideDownAction);
	this->contextMenu->insertSeparator(this->editAction);
 }

void BuildingObjectGraphicsItemWindow::updateContextMenu() {
	BuildingObjectGraphicsItem::updateContextMenu();
 }

void BuildingObjectGraphicsItemWindow::contextMenuAction( QAction* selectedAction ) {
	if ( selectedAction == this->slideUpAction ) {
		raiseMessage( new Request(_Window_METHOD_slide_up) );
		return;
	 }
	else if ( selectedAction == this->slideDownAction ) {
		raiseMessage( new Request(_Window_METHOD_slide_down) );
		return;
	 }
	BuildingObjectGraphicsItem::contextMenuAction(selectedAction);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void parseString( const QString& verStr, double& x, double& y )
 {
	if ( !verStr.startsWith("(") || !verStr.endsWith(")") )
		return;
	QStringList pointList = verStr.mid(1, verStr.size()-2).trimmed().split(",", QString::SkipEmptyParts);
	if ( pointList.size() < 2 )
		return;
	x = pointList.at(0).toDouble();// in cm
	y = pointList.at(1).toDouble();// in cm
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 }; // namespace gui
}; // namespace wosh
